package org.example.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.log4j.Log4j;
import org.apache.ibatis.session.SqlSession;
import org.example.mapper.UserMapper;
import org.example.model.UserModel;
import org.example.service.UserService;
import org.example.utils.CommonUtils;
import org.example.utils.ExecutorConfig;
import org.example.utils.SqlContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.ClientInfoStatus;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author zhanghao
 * @create 2024-01-22 11:20
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserModel> implements UserService {


    @Resource
    SqlContext sqlContext;

    /**
     * 测试多线程
     * @param userModelList
     */
    @Transactional
    @Override
    public void saveThread(List<UserModel> userModelList) {
        try {
            //先做删除操作，如果子线程出现异常，此操作不会回滚
            this.getBaseMapper().delete(null);
            //获取线程池
            ExecutorService service = ExecutorConfig.getThreadPool();
            //拆分数据，拆分五分
            List<List<UserModel>> lists = CommonUtils.averageAssign(userModelList,5);
            //执行的线程
            Thread [] threadArray = new Thread[lists.size()];
            //监控子线程执行完毕，在执行主线程，要不会先导致主线程关闭，子线程也会随着关闭
            CountDownLatch countDownLatch = new CountDownLatch(lists.size());
            AtomicBoolean atomicBoolean = new AtomicBoolean(true);
            for (int i = 0; i < lists.size(); i++) {
                if(i == lists.size() - 1){
                    atomicBoolean.set(false);
                }
                List<UserModel> list = lists.get(i);
                threadArray[i] = new Thread(() -> {
                    try {
                        //最后一个线程抛出异常
                        if(!atomicBoolean.get()){
                            throw new RuntimeException("抛出异常。。。。。");
                        }
                        //批量添加，mybatisPlus中自带的batch方法
                        this.saveBatch(list);
                    }finally {
                        countDownLatch.countDown();
                    }
                });
            }
            for (int i = 0; i < lists.size(); i++) {
                service.execute(threadArray[i]);
            }
            //当子线程执行完毕时，主线程再往下执行
            countDownLatch.await();
            System.out.println("添加完毕");
        }catch (Exception e){
            System.out.println("error:{}"+e);
            throw new RuntimeException("catch 出现异常");
        }
//        finally {
//            connection.close();
//        }

    }

    @Override
    public void saveThreadTransaction(List<UserModel> userModelList) throws SQLException {
        //获取数据库连接，获取会话（内部自由事务），
        SqlSession sqlSession = sqlContext.getSqlSession();
        Connection connection = sqlSession.getConnection();
        try {
            //设置手动提交
            connection.setAutoCommit(false);
            //获取mapper
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //先做删除操作
            userMapper.delete(null);
            //获取执行器
            ExecutorService service = ExecutorConfig.getThreadPool();
            List<Callable<Integer>> callableList = new ArrayList<>();
            //拆分list
            List<List<UserModel>> lists = CommonUtils.averageAssign(userModelList,5);
            AtomicBoolean atomicBoolean = new AtomicBoolean(true);
            for (int i = 0; i < lists.size(); i++) {
                if( i == lists.size() - 1){
                    atomicBoolean.set(false);
                }
                List<UserModel> list = lists.get(i);
                //使用返回结果的callable去执行
                Callable<Integer> callable = () -> {
                    //让最后一个线程抛出异常
                    if(!atomicBoolean.get()){
                        throw new RuntimeException("出现异常");
                    }
                    return userMapper.saveBatch(list);
                };
                callableList.add(callable);
            }
            //执行子线程
            List<Future<Integer>> futures = service.invokeAll(callableList);
            for (Future<Integer> future : futures) {
                //如果有一个执行不成功，那么就全部回滚
                if(future.get() <= 0){
                    connection.rollback();
                    return;
                }
            }
            connection.commit();
            System.out.println("添加完毕");
        }catch (Exception e){
            connection.rollback();
            throw new RuntimeException("catch 抛出异常");
        }finally {
            connection.close();
        }
    }
}
